//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include <Math.h>
#include "eval.h"
//---------------------------------------------------------------------------

static char ibuf[BUFSIZE];
static char *ibp;

int boolean = 0;
/*       conditon of UngetToken  if ( boolean == 1 ) have UngetToken
                          else boolean == 0 not have UngetToken
*/
static double pre_val;     // pre value
static int pre_type;       //pre type

/****************************************************************

		lexical analysis

******************************************************************/
/********************************************************************
       Get nextToken  if Token type is separted Const , Function
        Unary Operator etc.....
        and type mismatch return UnKnown
*********************************************************************/

int GetNextToken(double *value)
{
	double x;
	double y;

        if( boolean == 1 ){    /*  if have preToken    */
		*value = pre_val;
                boolean = 0;        //This setting is don't have preToken   
		return pre_type;
	}
        else {          /* if don't have preToken  */
                   //Function
                if( strstr(ibp,"sin(") == ibp ){ 
			ibp +=4;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = sin(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"cos(") == ibp ){
			ibp +=4;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = cos(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"tan(") == ibp ){
			ibp +=4;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = tan(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"asin(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = asin(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"acos(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = acos(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"atan(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = atan(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"sinh(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = sinh(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"cosh(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = cosh(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"tanh(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = tanh(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"exp(") == ibp ){
			ibp +=4;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = exp(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"log(") == ibp ){
			ibp +=4;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = log(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"log10(") == ibp ){
			ibp +=6;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = log10(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"pow(") == ibp ){
			ibp +=4;
			x = strtod(ibp,&ibp);
			if( strstr(ibp,",") == ibp ){
				++ibp;
				y = strtod(ibp,&ibp);
				if(*ibp ==')'){
					++ibp;
					*value = pow(x,y);
					pre_val = *value;
					pre_type = TK_FUNCTION;
					return TK_FUNCTION;
				}
				else
					return TK_UNKNOWN;
		       }
		       else return TK_UNKNOWN;
		}
		else if( strstr(ibp,"sqrt(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = sqrt(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"ceil(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = ceil(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"floor(") == ibp ){
			ibp +=6;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = floor(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
		}
		else if( strstr(ibp,"fabs(") == ibp ){
			ibp +=5;
			x = strtod(ibp,&ibp);
			if(*ibp ==')'){
				++ibp;
				*value = fabs(x);
				pre_val = *value;
				pre_type = TK_FUNCTION;
				return TK_FUNCTION;
			}
			else
				return TK_UNKNOWN;
                }    //some char
		else if( strstr(ibp,"+") == ibp ){
			++ibp;
                        /* *value  = undefined  */
			pre_type = TK_PLUS;
			return TK_PLUS;
		}
		else if( strstr(ibp,"-") == ibp ){
			++ibp;
			/* *value = undefined  */
			pre_type = TK_MINUS;
			return TK_MINUS;
		}
		else if( strstr(ibp,"*") == ibp ){
			++ibp;
			/*  *value = undefined  */
			pre_type = TK_STAR;
			return TK_STAR;
		}
		else if( strstr(ibp,"/") == ibp ){
			++ibp;
			/*  *value = undefined  */
			pre_type = TK_SLASH;
			return TK_SLASH;
		}
		else if( strstr(ibp,"(") == ibp ){
			++ibp;
			/*  *value = undefined  */
			pre_type = TK_LPAREN;
			return TK_LPAREN;
		}
		else if( strstr(ibp,")") == ibp ){
			++ibp;
                        /*  *value = undefined  */       
			pre_type = TK_RPAREN;
			return TK_RPAREN;
		}
                // Const
		else if( strstr(ibp,"0") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"1") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"2") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"3") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"4") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"5") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"6") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"7") == ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"8") ==ibp ) {
			x = strtod(ibp,&ibp);
				*value = x;
				pre_val = *value;
				pre_type = TK_CONST;
				return TK_CONST;
		}
		else if( strstr(ibp,"9" ) == ibp ) {
			x = strtod(ibp,&ibp);
			*value = x;
			pre_val = *value;
			pre_type = TK_CONST;
			return TK_CONST;
		}
		else if( strstr(ibp,"." ) == ibp ) {
			x = strtod(ibp,&ibp);
			*value = x;
			pre_val = *value;
			pre_type = TK_CONST;
			return TK_CONST;
		}
                //if token is NULL
		else if( strstr(ibp,"\0") == ibp ){
			++ibp;
			pre_type = TK_EOF;
			return TK_EOF;
		}

	}
	return TK_UNKNOWN;
        //if not reach over code
        //        then Unknown
}

/******************************************************************
        if call UngetToken
                then  recived pre stored value and
                 setting is change.
********************************************************************/

void UngetToken()
{
	boolean = 1;
}

/******************************************************************
      if input string have WhiteSpace
               skip the WhiteSpace
       and, convert lower char.
********************************************************************/

double EvalExpr(char *s)
{
	int i=0,j=0;

	boolean = 0;
	while(s[i] != NULL)
	{
                /* if s[i] is W.S then skip */
		while(  isspace(s[i]) != 0  )
		{
			i++;
		}
                ibuf[j] = s[i];    // copy
		j++;
		i++;
	}
        ibuf[j] = NULL;   // End of mark
	i = 0;
        /* convert lower char  */
	while(ibuf[i] != NULL)
	{
		ibuf[i] = tolower(ibuf[i]);
		i++;
	}
	ibp = ibuf;

	   return AdditiveExpr();
 }
 /*************************************************************************

		 Syntectial Analysis

***************************************************************************/

 /* AdditiveExpr Function */
 double AdditiveExpr()
 {
	return AdditiveExpr1(MultiplicativeExpr());
 }

 /* Relation of multiplicative expr & additive expr */
 double AdditiveExpr1(double value)
 {
	int tokenType;
	double tokenValue;

	tokenType = GetNextToken(&tokenValue);
	switch(tokenType){

		case TK_PLUS :
			return AdditiveExpr1(value + MultiplicativeExpr());
		case TK_MINUS :
			return AdditiveExpr1(value - MultiplicativeExpr());
		default :
			UngetToken();    /* NONE, so that Token return */ 
			return value;
	}
 }

/* Multiplicative Expr  */
 double MultiplicativeExpr()
 {
	return MultiplicativeExpr1( UnaryExpr() );
 }

 /* Relation of multiplicative expr & unary expr */
 double MultiplicativeExpr1(double value)
 {
	int tokenType;
	double tokenValue;

	tokenType = GetNextToken(&tokenValue);
	switch(tokenType){

		case TK_STAR :
			return MultiplicativeExpr1(value * UnaryExpr());
		case TK_SLASH :
        	if (UnaryExpr()==0) return 0;
			return MultiplicativeExpr1(value / UnaryExpr());
		default :
			UngetToken();     /* NONE, so that Token return */ 
			return value;
	}

 }

 double UnaryExpr()
 {
	int tokenType;
	double tokenValue;

	tokenType = GetNextToken(&tokenValue);
	switch(tokenType){

		case TK_PLUS :
			return PrimaryExpr();
		case TK_MINUS :
			return -PrimaryExpr();
		default :
			UngetToken();          /* NONE, so that Token return */ 
			return PrimaryExpr();
	}

 }

/* sometimes end of recursive, so error check  */
double PrimaryExpr()
{
	 int tokenType;
	 double tokenValue;
	 double value;

	 switch (tokenType = GetNextToken(&tokenValue)) {

		 case TK_CONST :
		 case TK_FUNCTION :
			 return tokenValue;

		 case TK_LPAREN :
			 value = AdditiveExpr();
			 tokenType = GetNextToken(&tokenValue);
			 if (tokenType == TK_RPAREN)
				 return (value);
			 else {
				 fprintf(stderr,"Error: ')' is expected.\n");
				 return(0);
			 }

		 case TK_PLUS :
			 fprintf(stderr, "Error: unexpected '+' symbol.\n");
			 return(0);

		 case TK_MINUS :
			 fprintf(stderr, "Error: unexpected '-' symbol.\n");
			 return(0);

		 case TK_STAR :
			 fprintf(stderr, "Error: unexpected '*' symbol.\n");
			 return(0);

		 case TK_SLASH :
			 fprintf(stderr, "Error: unexpected '/' symbol.\n");
			 return(0);

		 case TK_RPAREN :
			 fprintf(stderr, "Error: '(' or expression is missing.\n");
			 return(0);

		 case TK_EOF :
			 fprintf(stderr, "Error: incomplete expression.\n");
			 return(0);

		 default :
			 fprintf(stderr, "Error: unknown token is found.\n");
			 return(0);
	 }
}

